package com.zzyl.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.PendingTasksConstant;
import com.zzyl.dto.PendingTasksDto;
import com.zzyl.entity.CheckIn;
import com.zzyl.entity.PendingTasks;
import com.zzyl.entity.User;
import com.zzyl.mapper.HiActinstMapper;
import com.zzyl.service.ActFlowCommService;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.utils.StringUtils;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author sjqn
 * @date 2023/11/9
 */
@Service
public class ActFlowCommServiceImpl implements ActFlowCommService {

    @Autowired
    private TaskService taskService;

    @Autowired
    private RuntimeService runtimeService;

    /**
     * 获取下一个审核人
     *
     * @param processDefinitionKey
     * @param businessKey
     * @return
     */
    @Override
    public Long getNextAssignee(String processDefinitionKey, String businessKey) {
        Task task = taskService.createTaskQuery()
                .processDefinitionKey(processDefinitionKey)
                .processInstanceBusinessKey(businessKey).singleResult();
        if (task != null) {
            return Long.valueOf(task.getAssignee());
        }
        return null;
    }

    /**
     * 启动流程实例，并且自动执行首页点
     *
     * @param id                   业务id
     * @param user                 当前登录用户
     * @param processDefinitionKey 流程定义的key
     * @param variables            流程变量参数
     * @param isAuto               是否自动完成
     */
    @Override
    public void start(Long id, User user, String processDefinitionKey, Map<String, Object> variables, boolean isAuto) {
        //启动流程实例
        String businessKey = processDefinitionKey + ":" + id;
        variables.put("bussinessKey", businessKey);
        runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);

        //查询任务，执行任务
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey(processDefinitionKey)
                .processInstanceBusinessKey(businessKey)
                .taskAssignee(user.getId().toString())
                .list();
        //判断是否是首节点
        list = list.stream().filter(t -> "0".equals(t.getFormKey())).collect(Collectors.toList());
        if (!CollectionUtil.isEmpty(list) && isAuto) {
            //执行任务
            for (Task task : list) {
                Map<String, Object> variables2 = new HashMap<>();
                variables2.put("processStatus", 1);
                variables2.put("ops", 1);
                taskService.complete(task.getId(), variables2);
            }
        }
    }

    @Autowired
    private HistoryService historyService;

    /**
     * 分页条件查询我的任务列表（待办 | 我的申请）
     *
     * @param pendingTasksDto
     * @return
     */
    @Override
    public PageResponse<PendingTasks> getMyTaskList(PendingTasksDto pendingTasksDto) {

        HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery();


        //是否是已处理
        if (ObjectUtil.isNotEmpty(pendingTasksDto.getIsHandle())) {
            if (pendingTasksDto.getIsHandle() == 1) {
                taskQuery.finished();
            } else {
                taskQuery.unfinished();
            }
        }


        if(ObjectUtil.isNotEmpty(pendingTasksDto.getApplicatId())){
            //申请人
            taskQuery.taskAssignee(pendingTasksDto.getApplicatId().toString());
            //根据节点进行模糊查询
            taskQuery.taskNameLike("%申请");
        }else {
            //申请人
            taskQuery.taskAssignee(pendingTasksDto.getAssigneeId().toString());
            //根据节点进行模糊查询
            taskQuery.taskNameLike("%处理");
        }


        //查询条件
        //单据编号
        if (ObjectUtil.isNotEmpty(pendingTasksDto.getCode())) {
            //判断流程变量中的参数
            taskQuery.processVariableValueEquals("processCode", pendingTasksDto.getCode());
        }

        //单据类别
        if (ObjectUtil.isNotEmpty(pendingTasksDto.getType())) {
            //判断流程变量中的参数
            taskQuery.processVariableValueEquals("processType", pendingTasksDto.getType());
        }

        //流程状态
        if (ObjectUtil.isNotEmpty(pendingTasksDto.getStatus())) {
            //判断流程变量中的参数
            taskQuery.processVariableValueEquals("processStatus", pendingTasksDto.getStatus());
        }

        //时间范围
        if (ObjectUtil.isNotEmpty(pendingTasksDto.getStartTime())
                && ObjectUtil.isNotEmpty(pendingTasksDto.getEndTime())) {
            taskQuery.taskCreatedAfter(pendingTasksDto.getStartTime()).taskCreatedBefore(pendingTasksDto.getEndTime());
        }

        //获取总条数
        long count = taskQuery.count();

        //分页
        taskQuery.orderByHistoricTaskInstanceEndTime()
                .desc().listPage((pendingTasksDto.getPageNum() - 1) * pendingTasksDto.getPageSize(), pendingTasksDto.getPageSize());

        //返回内容
        List<HistoricTaskInstance> list = taskQuery.includeProcessVariables().list();

        List<PendingTasks> pendingTasksList = new ArrayList<>();

        for (HistoricTaskInstance task : list) {
            PendingTasks pendingTasks = new PendingTasks();

            Map<String, Object> processVariables = task.getProcessVariables();
            pendingTasks.setId(task.getId());//任务id

            pendingTasks.setCode(processVariables.get("processCode").toString());
            pendingTasks.setType(Integer.valueOf(processVariables.get("processType").toString()));
            pendingTasks.setStatus(Integer.valueOf(processVariables.get("processStatus").toString()));
            pendingTasks.setTitle(processVariables.get("processTitle").toString());
            pendingTasks.setApplicat(processVariables.get("assignee0Name").toString());
            pendingTasks.setAssigneeId(Long.valueOf(task.getAssignee()));

            //设置入住id  checkIn-new:12
            Long checkInId = Long.valueOf(processVariables.get("bussinessKey").toString().split(":")[1]);
            pendingTasks.setCheckInId(checkInId);

            LocalDateTime applicationTime = LocalDateTimeUtil.parse(processVariables.get("applicationTime").toString());
            pendingTasks.setApplicationTime(applicationTime);

            //处理完成时间
            if(!pendingTasks.getStatus().equals(PendingTasksConstant.TASK_STATUS_APPLICATION)){
                LocalDateTime finishTime = LocalDateTimeUtil.parse(processVariables.get("finishTime").toString());
                pendingTasks.setFinishTime(finishTime);
            }

            pendingTasksList.add(pendingTasks);
        }

        return PageResponse.of(pendingTasksList, pendingTasksDto.getPageNum(), pendingTasksDto.getPageSize(),
                (count + pendingTasksDto.getPageSize() - 1) / pendingTasksDto.getPageSize(), count);
    }

    /**
     * 判断当前任务的formKey是否与状态匹配
     * 没有考虑，前端传递的状态与数据库的状态
     * @param taskId
     * @param flowStatus
     * @return
     */
    @Override
    public Integer isCurrentUserAndStep(String taskId,Integer flowStatus,Integer dbFlowStatus) {

        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
        String formKey = historicTaskInstance.getFormKey();
        //流程状态与执行节点一致，返回1
        if(flowStatus.equals(dbFlowStatus)){
            if(formKey.equals(flowStatus.toString())){
                return 1;
            }
            return 0;
        }
        //返回2，代表可以撤回
        if(formKey.equals((dbFlowStatus-1) + "") && dbFlowStatus.equals(CheckIn.FlowStatus.CONFIG.getCode())){
            return 2;
        }

        // 其他情况返回1
        return 1;

    }

    /**
     * 完成任务
     * @param title  标题
     * @param taskId 任务id
     * @param userId 用户id
     * @param code   ops(1 通过  2 拒绝   3 驳回)
     * @param status 审核状态（ 1，申请中  2 已完成   3  已关闭）
     */
    @Override
    public void completeProcess(String title, String taskId, String userId, Integer code, Integer status) {

        //检验代码的健壮性，非空判断
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if(null == task){
            return;
        }

        //删除历史任务
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().processInstanceId(task.getProcessInstanceId()).list();

        if(CollectionUtil.isNotEmpty(list)){
            list.forEach(x->{
                //删除首页点的任务（如果code等于3，说明是驳回）
                if(code.equals(3) && "0".equals(x.getFormKey())){
                    historyService.deleteHistoricTaskInstance(x.getId());
                }
                //删除任务执行的下一个任务
                if(x.getFormKey().equals((Integer.parseInt(task.getFormKey())+1)+"")){
                    historyService.deleteHistoricTaskInstance(x.getId());
                }
            });
        }

        Map<String,Object> variable = new HashMap<>();

        if(ObjectUtil.isNotEmpty(code)){
            variable.put("ops",code);

        }

        if(ObjectUtil.isNotEmpty(title)){
            variable.put("processTitle",title);
        }

        if(ObjectUtil.isNotEmpty(status)){
            variable.put("processStatus",status);
            //完成时间
            variable.put("finishTime",LocalDateTime.now());
        }

        taskService.complete(taskId,variable);

    }

    /**
     * 撤销
     * @param taskId
     */
    @Override
    public void cancelProcess(String taskId) {

        String processInstanceId = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult().getProcessInstanceId();

        //设置流程变量
        Map<String,Object> variables = new HashMap<>();
        variables.put("finishTime",LocalDateTime.now());
        variables.put("processStatus",3);

        runtimeService.setVariables(processInstanceId,variables);

        runtimeService.deleteProcessInstance(processInstanceId,"申请人撤销了申请");

    }

    /**
     * 撤回任务
     *
     * @param taskId
     * @param first  是否默认退回流程第一个节点，true 是,false默认是上一个节点，
     */
    @Override
    public void withdrawTask(String taskId, boolean first) {
        anyJump(taskId, first);
    }

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private HiActinstMapper hiActinstMapper;

    /**
     * 跳转任意节点
     *
     * @param taskId 当前操作节点
     * @param first  是否默认第一 是否驳回
     */
    public void anyJump(String taskId, boolean first) {
        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
        //实例定义id：checkIn:1:0f97a26d-5697-11ee-bf3f-5405db5be13e
        String processDefinitionId = historicTaskInstance.getProcessDefinitionId();
        //实例id：16ea626d-5755-11ee-849a-5405db5be13e
        String processInstanceId = historicTaskInstance.getProcessInstanceId();
        // 对上一个节点和发起节点的支持:Activity_0pnd103
        String activityId = null;
        //找到需要驳回的节点中，比如：现在是：养老顾问-入住配置，那么要找的就是上一个节点：副院长-审批
        HistoricActivityInstance targetActivity = getRejectTargetActivity(null, processInstanceId, first);
        if (targetActivity != null) {
            activityId = targetActivity.getActivityId();
        }
        if (StrUtil.isEmpty(activityId)) {
            return;
        }
        try {
            //获取流程中的bpmn文件
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
            //流程实例
            Process process = bpmnModel.getMainProcess();
            // 解析调整的目标节点
            //找到目标节点  -->  副院长-审批
            FlowNode targetFlowNode = (FlowNode) process.getFlowElement(activityId);
            //找到当前节点的所有连线
            List<SequenceFlow> incomingFlows = targetFlowNode.getIncomingFlows();

            List<SequenceFlow> targetSequenceFlow = new ArrayList<>();
            //遍历所有连线
            for (SequenceFlow incomingFlow : incomingFlows) {
                //连线的入节点
                FlowNode source = (FlowNode) incomingFlow.getSourceFlowElement();
                List<SequenceFlow> sequenceFlows;
                if (source instanceof ParallelGateway) {// 如果是并行网关同级节点，则跳转到所有节点
                    sequenceFlows = source.getOutgoingFlows();
                } else {
                    sequenceFlows = source.getOutgoingFlows();// 否则直接跳转到对应节点，包括为执行过的节点
                }
                targetSequenceFlow.addAll(sequenceFlows);
            }
            //获取当前任务中的所有待执行的任务
            List<Task> list = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
            for (Task t : list) {
                //把一个任务动态转向目标节点
                //参数1：目标节点   参数2：当前任务   参数3：当前任务id    参数4:目标节点所有连线   参数5：默认flase，找上一个节点
                trunToTarget(process, t, first ? taskId : list.get(0).getId(), targetSequenceFlow, first);
            }
            if (!first) { // 撤回 删除最后的节点
                historyService.deleteHistoricTaskInstance(taskId);
                hiActinstMapper.deleteHiActivityInstByTaskId(taskId);
            } else {
                // 撤回 删除第一个
                List<HistoricTaskInstance> list1 = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).finished().orderByTaskCreateTime().asc().list();
                if (CollUtil.isNotEmpty(list1)) {
                    HistoricTaskInstance firstTask = list1.get(0);
                    historyService.deleteHistoricTaskInstance(firstTask.getId());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 把一个任务动态转向目标节点
     * @param process   目标节点
     * @param task  当前任务
     * @param taskId             当前任务id
     * @param targetSequenceFlow  目标节点所有连线
     * @param first  默认flase，找上一个节点
     */
    private void trunToTarget(Process process, TaskInfo task, String
            taskId, List<SequenceFlow> targetSequenceFlow, boolean first) {

        //当前节点:入住选配-处理
        FlowNode curFlowNode = (FlowNode) process.getFlowElement(task.getTaskDefinitionKey());
        if (curFlowNode == null) {
            //遍历节点中的所有子模块
            for (FlowElement flowElement : process.getFlowElements()) {
                if (flowElement instanceof SubProcess) {
                    SubProcess subProcess = (SubProcess) flowElement;
                    FlowElement fe = subProcess.getFlowElement(task.getTaskDefinitionKey());
                    if (fe != null) {
                        curFlowNode = (FlowNode) fe;
                        break;
                    }
                }
            }
        }
        //备份原始连线
        List<SequenceFlow> tempOutgoingSequenceFlows = new ArrayList<>(curFlowNode.getOutgoingFlows());
        //最新任务id与要删除的id一致
        if (taskId.equals(task.getId())) {
            //当前节点设置流出的连线
            curFlowNode.setOutgoingFlows(targetSequenceFlow);
            //完成当前任务
            taskService.complete(task.getId());
            if (!first) {
                //删除任务实例
                historyService.deleteHistoricTaskInstance(task.getId());
                //删除历史任务
                hiActinstMapper.deleteHiActivityInstByTaskId(task.getId());
            }
        }
        //恢复之前的连线
        curFlowNode.setOutgoingFlows(tempOutgoingSequenceFlows);
    }

    /**
     * 获取历史撤回或回退目标节点,支持上一节点，第一个节点
     *
     * @param taskId            要回退的taskId
     * @param processInstanceId
     * @return
     */
    private HistoricActivityInstance getRejectTargetActivity(String taskId, String processInstanceId, boolean first) {

        HistoricActivityInstance targetActivity = null;
        HistoricActivityInstanceQuery query = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("userTask");

        // 取得所有历史任务按时间降序排序
        List<HistoricActivityInstance> historicActivityInstances = null;
        if (first) {// 退到第一个节点
            historicActivityInstances = query.orderByHistoricActivityInstanceStartTime().asc().list();
            return historicActivityInstances.get(0);
        } else { // 找到最近一个节点
            historicActivityInstances = query.orderByHistoricActivityInstanceStartTime().desc().list();
        }

        if (CollectionUtils.isEmpty(historicActivityInstances) || historicActivityInstances.size() < 2) {
            return null;
        }
        if (!StringUtils.isBlank(taskId)) {
            return targetActivity;
        }
        // 不传活动id的情况直接找第一个任务
        // 最后一条是当前正在进行的任务 需要找到最近的但是名称和当前任务不一样的任务去撤回
        HistoricActivityInstance current = historicActivityInstances.get(0);
        for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
            if (!current.getActivityId().equals(historicActivityInstance.getActivityId())) {
                if (historicActivityInstance.getActivityType().equals("userTask")) {
                    targetActivity = historicActivityInstance;
                    break;
                }
            }
        }
        return targetActivity;
    }
}
